<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><style type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;">
<p style=" margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:xx-large; font-weight:600;">9. Классы </span></p>
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="aswift_0_expand"></a><a href="http://pythoner.name/documentation/tutorial/classes#a-word-about-names-and-objects"><span style=" text-decoration: underline; color:#0000ff;">9</span></a><span style=" text-decoration: underline; color:#0000ff;">.1. Несколько слов об именах и объектах</span> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#python-scopes-and-namespaces"><span style=" text-decoration: underline; color:#0000ff;">9.2. Области видимости и пространства имен в Python</span></a> </li>
<ul type="circle" style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 2;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#scopes-and-namespaces-example"><span style=" text-decoration: underline; color:#0000ff;">9.2.1. Примеры областей видимости и пространств имен</span></a> </li></ul>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#tut-firstclasses"><span style=" text-decoration: underline; color:#0000ff;">9.3. Первый взгляд на классы</span></a> </li>
<ul type="circle" style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 2;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#class-definition-syntax"><span style=" text-decoration: underline; color:#0000ff;">9.3.1. Синтаксис определения класса</span></a> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#class-objects"><span style=" text-decoration: underline; color:#0000ff;">9.3.2. Объекты класса</span></a> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#instance-objects"><span style=" text-decoration: underline; color:#0000ff;">9.3.3. Экземплярные объекты</span></a> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#method-objects"><span style=" text-decoration: underline; color:#0000ff;">9.3.4. Методы объектов</span></a> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#class-and-instance-variables"><span style=" text-decoration: underline; color:#0000ff;">9.3.5. Переменные класса и экземпляра</span></a> </li></ul>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#random-remarks"><span style=" text-decoration: underline; color:#0000ff;">9.4. Некоторые замечания</span></a> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#inheritance"><span style=" text-decoration: underline; color:#0000ff;">9.5. Наследование</span></a> </li>
<ul type="circle" style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 2;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#multiple-inheritance"><span style=" text-decoration: underline; color:#0000ff;">9.5.1. Множественное наследование</span></a> </li></ul>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#private-variables"><span style=" text-decoration: underline; color:#0000ff;">9.6. Приватные переменные</span></a> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#odds-and-ends"><span style=" text-decoration: underline; color:#0000ff;">9.7. Различные заметки</span></a> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#iterators"><span style=" text-decoration: underline; color:#0000ff;">9.8. Итераторы</span></a> </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#generators"><span style=" text-decoration: underline; color:#0000ff;">9.9. Генераторы</span></a> </li>
<li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/classes#generator-expressions"><span style=" text-decoration: underline; color:#0000ff;">9.10. Выражения генераторов</span></a></li></ul>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">По сравнению с другими языками программирования, механизм классов Python добавляет классы с минимумом нового синтаксиса и семантики. Это смесь механизмов класса похожая на C++ и Modula-3. Классы Python предоставляют все стандартные возможности объектно-ориентированного программирования: механизм наследования классов позволяет использовать несколько базовых классов, производный класс может переопределить любые методы своего базового класса или классов, а метод может вызвать метод базового класса с тем же именем. Объекты могут содержать произвольные количество и типы данных. Как и в случае модулей, классы используют динамическую природу Python: они создаются во время выполнения и могут быть изменены в дальнейшем после создания. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">В терминологии C++ обычно члены класса (в том числе данные) являются <span style=" font-style:italic;">public</span> (кроме см. ниже <a href="http://pythoner.name/documentation/tutorial/classes#private-variables"><span style=" text-decoration: underline; color:#0000ff;">Приватные переменные</span></a>), а все функции-члены являются <span style=" font-style:italic;">virtual</span>. Как и в Modula-3 отсутствуют сокращения для привязок (referencing) членов объекта из его методов: метод-функция объявляется с явным первым аргументом, представляющим объект, который неявно предоставляется вызовом. Как и в Smalltalk, классы сами являются объектами. Это обеспечивает семантику для импортирования и переименования. В отличие от C++ и Modula-3, встроенные типы могут быть использованы как базовые классы для расширения их пользователем. Также как и в C++ большинство встроенных операторов со специальным синтаксисом (арифметические операторы, индексирование и т.д.) могут быть переопределены для экземпляров класса. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(Из-за отсутствия общепринятой терминологии при разговоре о классах, я буду время от времени использовать термины Smalltalk и C++. Я хотел бы использовать терминологию Modula-3, так как его объектно-ориентированная семантика ближе к Python, чем C++, но мне кажется, что только некоторые читатели слышали о нем.) </p>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="a-word-about-names-and-objects"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.1. Несколько слов об именах и объектах</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">У объектов есть индивидуальность, и несколько имен (в несколько областях видимости) могут быть связаны с одним и тем же объектом. Это известно как использование псевдонимов (aliasing) в других языках. Обычно это не принимается во внимание при первом знакомстве с Python, и это можно спокойно игнорировать при работе с неизменными основными типами (числами, строками, кортежами). С другой стороны, использование псевдонимов предоставляет возможность неожиданного эффекта от семантики кода Python с участием изменяемых объектов, таких как списки, словари и множества других типов. Это обычно несет пользу для программы, так как псевдонимы в некоторых отношениях ведут себя как указатели. Например, передать объект легче, так как реализацией передается только указатель; и если функция изменяет объект, переданный в качестве аргумента, в вызывающей части кода будут наблюдаться изменения - это устраняет необходимость для двух различных механизмов передачи параметров как в Pascal. </p>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="python-scopes-and-namespaces"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.2. Области видимости и пространства имен в Python</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Перед введением в классы, сначала необходимо кое-что сказать о правилах областей видимости в Python. Определения классов выполняют небольшие аккуратные трюки с пространствами имен, и вы должны знать, как работают области видимости и пространства имен, чтобы хорошо понимать, что происходит. Кстати, знания в этой области полезны для любого продвинутого программиста на Python. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Давайте начнем с некоторых определений. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">namespace</span> (пространство имен) представляет собой отображение имен на объекты. Большинство пространств имен в настоящее время реализованы как словари Python, но в любом случае это обычно не заметно (за исключением производительности), и это может измениться в будущем. Примеры пространств имен: множество встроенных имен (содержащие такие функции, как abs() (docs.python.org/3/library/functions.html#abs) и встроенные имена исключений); глобальные имена в модуле и локальные имена в вызове функции. В определенном смысле набор атрибутов объекта также образует пространство имен. Важная деталь в знаниях о пространствах имен заключается в том, что нет абсолютно никакой связи между именами в разных пространствах; например, в двух различных модулях может быть определена функция <span style=" font-family:'Courier New,courier';">maximize</span>, и это не создаст путаницы - пользователи модулей должны использовать префикс в виде имени модуля перед именем функции. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Кстати, слово <span style=" font-style:italic;">attribute</span> я использую для любого имени после точки - например, в выражении <span style=" font-family:'Courier New,courier';">z.real</span>, <span style=" font-family:'Courier New,courier';">real</span> является атрибутом объекта <span style=" font-family:'Courier New,courier';">z</span>. Строго говоря, ссылки на имена в модулях - это ссылки атрибутов: в выражении <span style=" font-family:'Courier New,courier';">modname.funcname</span>, <span style=" font-family:'Courier New,courier';">modname</span> - это объект модуля, а <span style=" font-family:'Courier New,courier';">funcname</span> является его атрибутом. В этом случае существует простое отображение между атрибутами модуля и глобальными именами, определенными в модуле: они разделяют одно и то же пространство имен! <a name="id1"></a><a href="http://pythoner.name/documentation/tutorial/classes#id11"><span style=" text-decoration: underline; color:#0000ff;">[</span></a><span style=" text-decoration: underline; color:#0000ff;">1]</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Атрибуты могут быть только для чтения или изменяемыми. В последнем случае, возможно присвоение атрибутов. Атрибуты модуля доступны для записи: вы можете написать <span style=" font-family:'Courier New,courier';">modname.the_answer = 42</span>. Записываемые атрибуты могут также быть удалены с помощью оператора del (docs.python.org/3/reference/simple_stmts.html#del). Например, <span style=" font-family:'Courier New,courier';">del modname.the_answer</span> удалит атрибут <span style=" font-family:'Courier New,courier';">the_answer</span> у объекта <span style=" font-family:'Courier New,courier';">modname</span>. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Пространства имен создаются в различные моменты времени и имеют разные периоды жизни. Пространство, содержащее встроенные имена, создается, когда запускается интерпретатор Python, и никогда не удаляется. Глобальное пространство имен для модуля создается, когда определение модуля считывается; обычно пространство имен модуля также существует до выхода из интерпретатора. Операторы, выполняющиеся на высшем уровне вызова интерпретатора, либо читающиеся из файла скрипта или интерактивно, рассматриваются как часть модуля под названием __main__ (docs.python.org/3/library/__main__.html#module-__main__), поэтому они имеют свое собственные глобального пространство имен. (Встроенные имен на самом деле находятся в модуле, который называется builtins (docs.python.org/3/library/builtins.html#module-builtins).) </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Локальное пространство имен функции создается при ее вызове и удаляется, когда функция возвращает управление или вызывает исключение, которое не обрабатывается внутри нее. (Действительно, забывчивость была бы лучшим способом описать то, что происходит на самом деле.) Конечно, рекурсивные вызовы имеют свои собственные локальные имена. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">scope (область видимости) является буквальной областью Python-программы, где непосредственно доступно пространство имен. &quot;Непосредственно доступно&quot; здесь означает, что &quot;неспецифическая&quot; ссылка на имя пытается найти имя в пространстве имен. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Хотя области (scopes) определяются статически, но используются динамически. В любое время выполнения есть по крайней мере три вложенные области видимости, чьи пространства имен доступны сразу: </p>
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">внутренняя область видимости, которая просматривается в первую очередь, содержит локальные имена </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">область любых ограждающих функций, которая просматривается, начиная с ближайшей области видимости, содержит нелокальные, но и неглобальные имена </li>
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">предпоследняя область видимости включает глобальные имена текущего модуля </li>
<li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">внешняя область (исследуется последней) является пространством имен, содержащем встроенные имена</li></ul>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Если имя объявлено как глобальное, то все ссылки и присвоения переходят непосредственно к средней области видимости, содержащей глобальные имена модуля. Для переназначения переменных, находящихся вне внутренней области видимости, может быть использован оператор nonlocal (docs.python.org/3/reference/simple_stmts.html#nonlocal); если такого объявления нет, эти переменные доступны только для чтения (попытка записи в такую переменную будет просто создавать новую локальную переменную в самой внутренней области видимости, в результате чего внешняя переменная с таким же именем остается без изменений). </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Обычно локальная область ссылается на локальные имена (текстуально) текущей функции. Вне функций ссылки локальной области - то же самое, что пространство имен глобальной области: пространство имен модуля. Определения классов размещают еще одно пространство имен в локальной области. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Важно понимать, что области видимости определяются текстуально: глобальная область функции, определенной в модуле, есть пространство имен этого модуля, независимо от того, где и под каким псевдонимом вызывается функция. С другой стороны, фактический поиск имен производится динамически, во время выполнения. Тем не менее, определение языка развивается в сторону статического разрешения имен, ко времени &quot;компиляции&quot;, так что не полагайтесь на динамическое разрешение имен! (На самом деле, локальные переменные уже определены статически.) </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Специальная причуда Python - если нет оператора global, присвоения имен всегда идут в самые внутренние области. Присваивания не копируют данные - они просто связывают имена с объектами. То же самое верно для удалений: оператор del x убирает привязку х из пространства имен, на которые ссылается локальная область видимости. На самом деле все операции, которые вводят новые имена используют локальную область: в частности, оператор import (docs.python.org/3/reference/simple_stmts.html#import) и определения функций связывают модуль или имя функции в локальной области видимости. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Оператор global может быть использован для указания, какие определенные переменные находятся в глобальной области и должны быть отосланы туда; оператор nonlocal указывает, что некоторые переменные находятся в огражденной области видимости и должны быть отосланы туда. </p>
<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="scopes-and-namespaces-example"></a><span style=" font-size:large; font-weight:600;">9</span><span style=" font-size:large; font-weight:600;">.2.1. Пример областей видимости (scopes) и пространств имен (namespaces)</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Это пример демонстрирует, как ссылаться на различные области и пространства имен, и как global и nonlocal влияют на связывание переменных: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">def scope_test():</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def do_local():</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        spam = &quot;local spam&quot;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def do_nonlocal():</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        nonlocal spam</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        spam = &quot;nonlocal spam&quot;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def do_global():</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        global spam</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        spam = &quot;global spam&quot;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    spam = &quot;test spam&quot;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    do_local()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(&quot;After local assignment:&quot;, spam)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    do_nonlocal()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(&quot;After nonlocal assignment:&quot;, spam)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    do_global()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(&quot;After global assignment:&quot;, spam)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">scope_test()</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">print(&quot;In global scope:&quot;, spam)</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Вывод данного примера будет таким: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">After local assignment: test spam</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">After nonlocal assignment: nonlocal spam</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">After global assignment: nonlocal spam</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">In global scope: global spam</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Заметьте, что присвоение local (которое происходит по умолчанию) не изменило связывания spam в scope_test. Присвоение nonlocal изменило связывание spam в scope_test, и присвоение global изменило связывание до уровня модуля. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Вы также можете видеть, что не было никакого предварительного связывания spam до присваивания global. </p>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="tut-firstclasses"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.3. Первый взгляд на классы</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Классы вводят немного нового синтаксиса, три новых объектных типа и некоторую новую семантику. </p>
<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="class-definition-syntax"></a><span style=" font-size:large; font-weight:600;">9</span><span style=" font-size:large; font-weight:600;">.3.1. Синтаксис определения класса</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Простейшая форма определения класса выглядит следующим образом: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class ClassName:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    &lt;statement-1&gt;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    &lt;statement-N&gt;</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Определения классов, как и определения функций (операторы def (docs.python.org/3/reference/compound_stmts.html#def)), должны быть выполнены до их вызова. (Предположительно вы может поместить определение класса в ветке оператора if (docs.python.org/3/reference/compound_stmts.html#if) или внутри функции.) </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">На практике операторы внутри определения класса, как правило, будут определениями функций, но другие выражения разрешены также, а иногда и полезны - мы вернемся к этому позже. Определения функций внутри класса обычно имеют своеобразную форму списка аргументов, продиктованную соглашениями по вызову методов - опять же, это объясняется позже. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Когда определение класса введено, создается новое пространство имен и используется в качестве локальной области видимости - поэтому все присваивания локальным переменным происходят в этом новом пространстве имен. В частности определения функций связываются с именем новой функции здесь. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Когда определение класса остается обычным (через завершение), создается объект класса. В основном это обертка вокруг содержимого пространства имен, созданного определением класса; мы узнаем больше об объектах класса в следующем разделе. Первоначальная локальная область видимости (в действительности она была введена как раз перед определением класса) будет восстановлена​​, и объект класса связан здесь с именем класса, данным в заголовке определения класса (ClassName в примере). </p>
<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="class-objects"></a><span style=" font-size:large; font-weight:600;">9</span><span style=" font-size:large; font-weight:600;">.3.2. Объекты класса</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Объекты класса поддерживают два вида операций: ссылки на атрибуты и экземпляры. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ссылки на атрибуты используют стандартный синтаксис, используемый для всех ссылок на атрибуты в Python: <span style=" font-family:'Courier New,courier';">obj.name</span>. Допустимыми именами атрибутов являются все имена, которые были в пространстве имен класса, когда был создан объект класса. Таким образом, если определение класса выглядит так: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class MyClass:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    &quot;&quot;&quot;A simple example class&quot;&quot;&quot;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    i = 12345</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def f(self):</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        return 'hello world'</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">тогда <span style=" font-family:'Courier New,courier';">MyClass.i</span> и <span style=" font-family:'Courier New,courier';">MyClass.f</span> правильные ссылки на атрибуты, возвращающие целое число и объект-функцию соответственно. Атрибуты класса также могут быть назначены, так что вы можете изменить значение <span style=" font-family:'Courier New,courier';">MyClass.i</span> с помощью присвоения. <span style=" font-family:'Courier New,courier';">__doc__</span> также является доступным атрибутом, возвращающим строку документации, принадлежащей классу: <span style=" font-family:'Courier New,courier';">&quot;A simple example class&quot;</span>. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Экземпляр класса использует нотацию в виде функции. Просто делается вид, что объект класса - это функция без параметров, которая возвращает новый экземпляр класса. Например (предполагая, класс выше): </p>
<pre style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">x = MyClass()</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">создается новый экземпляр класса, и этот объект присваивается локальной переменной <span style=" font-family:'Courier New,courier';">х</span>. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Операция создания экземпляра (вызов объекта класса) создает пустой объект. Многие классы при создании экземпляров настроены на определенное исходное состояние. Поэтому в классе может быть определен специальный метод с именем <span style=" font-family:'Courier New,courier';">__init__()</span> (docs.python.org/3/reference/datamodel.html#object.__init__), например: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">def __init__(self):</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    self.data = []</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Если класс определяет метод __init__(), он автоматически вызывается при создании экземпляра класса. В данном примере новый инициализированный экземпляр может быть получен так: </p>
<pre style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">x = MyClass()</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Конечно, для большей гибкости метод  <span style=" font-family:'Courier New,courier';">__init__()</span> может иметь аргументы. В этом случае аргументы, переданные оператору создания экземпляра класса, передаются в <span style=" font-family:'Courier New,courier';">__init__()</span>. Пример: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; class Complex:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">...     def __init__(self, realpart, imagpart):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">...         self.r = realpart</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">...         self.i = imagpart</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">...</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; x = Complex(3.0, -4.5)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; x.r, x.i</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">(3.0, -4.5)</span> </pre>
<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="instance-objects"></a><span style=" font-size:large; font-weight:600;">9</span><span style=" font-size:large; font-weight:600;">.3.3. Объекты экземпляров</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Теперь что мы можем делать с объектами экземпляров? Допустимы только операции, представляющие собой ссылки на атрибуты объекта. Есть два вида допустимых имен атрибутов, атрибуты данных и методы. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">data attributes</span> (атрибуты данных) соответствуют &quot;переменным экземпляра&quot; в Smalltalk, а также &quot;элементам данных&quot; в C++. Нет необходимости объявлять атрибуты данных; как локальные переменные, они начинают существовать, когда им впервые происходит присваивание. Например, если <span style=" font-family:'Courier New,courier';">х</span> является экземпляром <span style=" font-family:'Courier New,courier';">MyClass</span>, созданного выше, следующий фрагмент кода выведет значение 16: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">x.counter = 1</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">while x.counter &lt; 10:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    x.counter = x.counter * 2</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">print(x.counter)</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">del x.counter</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Другой вид ссылки на атрибут экземпляра - это <span style=" font-style:italic;">method</span>. Метод является функцией, которая &quot;принадлежит&quot; объекту. (В Python, термин метод не является уникальным для экземпляров класса: другие типы объектов также могут иметь методы. Например, объекты списка имеют методы, называемые append, insert, remove, sort (добавление, вставка, удаление, сортировка) и т. д. Тем не менее в последующем обсуждении мы будем использовать термин <span style=" font-style:italic;">метод</span> исключительно для обозначения методов объектов-экземпляров класса, если явно не указано иное.) </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Допустимые имена методов объекта-экземпляра зависят от его класса. По определению, все атрибуты класса, которые являются объектами-функциями, определяют соответствующие методы его экземпляров. Так в нашем примере, <span style=" font-family:'Courier New,courier';">x.f</span> является допустимой ссылкой-методом, так как <span style=" font-family:'Courier New,courier';">MyClass.f</span> является функцией, но не <span style=" font-family:'Courier New,courier';">x.i</span>, так как <span style=" font-family:'Courier New,courier';">MyClass.i</span> не является. Но <span style=" font-family:'Courier New,courier';">x.f</span> - это не то же самое, что и <span style=" font-family:'Courier New,courier';">MyClass.f</span> - это метод-объект, а не функция-объект. </p>
<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="method-objects"></a><span style=" font-size:large; font-weight:600;">9</span><span style=" font-size:large; font-weight:600;">.3.4. Объекты метода</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Обычно метод вызывается сразу после точки: </p>
<pre style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">x.f()</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">В <span style=" font-family:'Courier New,courier';">MyClass</span>, например, такой вызов вернет строку <span style=" font-family:'Courier New,courier';">'hello world'</span>. Тем не менее, нет необходимости вызывать метод сразу: <span style=" font-family:'Courier New,courier';">x.f</span> является методом- объектом, и может быть сохранен в &quot;стороне&quot; и вызываться позже. Например: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">xf = x.f</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">while True:</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(xf())</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">будет продолжать выводить <span style=" font-family:'Courier New,courier';">hello world</span> до конца времени. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Что именно происходит, когда вызывается метод? Вы могли заметить, выше <span style=" font-family:'Courier New,courier';">x.f()</span> был вызван без аргумента, при том, что в определении функции <span style=" font-family:'Courier New,courier';">f()</span> указывается аргумент. Что случилось с аргументом? Конечно Python генерирует исключение, когда функция, которая требует аргумент вызывается без него - даже если аргумент фактически не используется... </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">На самом деле, вы могли уже догадаться: особенность метода в том, что объект передается в качестве первого аргумента функции. В нашем примере вызов <span style=" font-family:'Courier New,courier';">x.f()</span> в точности эквивалентно <span style=" font-family:'Courier New,courier';">MyClass.f(х)</span>. В общем, вызов метода со списком <span style=" font-style:italic;">n</span> аргументов эквивалентен вызову соответствующей функции со списком аргументов, который создается путем введения объекта метода перед первым аргументом. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Если вы все еще не понимаете, как работают методы, взгляд на реализацию, возможно прояснит ситуацию. Когда ссылаются на атрибут экземпляра, который не является атрибутом данных, ищется его класс. Если имя обозначает действительный атрибут класса, который является объектом-функцией, метод-объект создается упаковкой (указателями на) объект-экземпляр и объект-функцию только что вошедших вместе в абстрактный объект: это метод-объект. Когда объект метода вызывается со списком аргументов, новый список аргументов строится из объекта-экземпляра и списка аргументов, и объект-функция вызывается с этим новым списком аргументов. </p>
<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="class-and-instance-variables"></a><span style=" font-size:large; font-weight:600;">9</span><span style=" font-size:large; font-weight:600;">.3.5. Переменные класса и экземпляра</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Вообще говоря, данные переменных экземпляра уникальны для каждого экземпляра, а атрибуты и функции переменных класса разделяются всеми экземплярами класса: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class Dog:</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    kind = 'canine'         # переменная класса разделяется всеми экземплярами</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def __init__(self, name):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.name = name    # переменная экземпляра уникальна для каждого</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d = Dog('Fido')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; e = Dog('Buddy')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d.kind                  # разделяется всеми собаками</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">'canine'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; e.kind                  # разделяется всеми собаками</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">'canine'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d.name                  # уникальна для d</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">'Fido'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; e.name                  # уникальна для e</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">'Buddy</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Как уже говорилось в разделе 9.1., разделяемые данные могут иметь возможно неожиданные эффекты в случае привлечения изменяемых (docs.python.org/3/glossary.html#term-mutable) объектов, таких как списки и словари. Например, список tricks в следующем коде не должен быть использован как переменная класса просто потому, что единственный список будет разделяться всеми экземплярами Dog: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class Dog:</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    tricks = []             # ошибочное использование переменной класса</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def __init__(self, name):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.name = name</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def add_trick(self, trick):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.tricks.append(trick)</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d = Dog('Fido')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; e = Dog('Buddy')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d.add_trick('roll over')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; e.add_trick('play dead')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d.tricks                # неожиданно разделяется всеми собаками</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">['roll over', 'play dead']</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Вместо этого в корректной разработке класса следует использовать переменную экземпляра: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class Dog:</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def __init__(self, name):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.name = name</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.tricks = []    # создает новый пустой список для каждой собаки</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def add_trick(self, trick):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.tricks.append(trick)</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d = Dog('Fido')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; e = Dog('Buddy')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d.add_trick('roll over')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; e.add_trick('play dead')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; d.tricks</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">['roll over']</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; e.tricks</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">['play dead']</span> </pre>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="random-remarks"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.4. Некоторые замечания</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Атрибуты данных переопределяют атрибуты метода с тем же именем; чтобы избежать случайных конфликтов имен, которые могут привести к трудно обнаруживаемым ошибкам в больших программах, имеет смысл использовать какое-либо соглашение, которое свело бы к минимуму вероятность подобных конфликтов. Это может быть использование большой первой буквы для имен методов, предварение имен атрибутов данных небольшой уникальной строкой (возможно, просто подчеркивание), или использование глаголов для методов и существительных для атрибутов данных. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">На атрибуты данных могут ссылаться методы, а также обычные пользовательские (&quot;клиенты&quot;) объекты. Другими словами, классы не могут быть использованы для реализации чисто абстрактных типов данных. На самом деле ничто в Python не позволяет обеспечить соблюдение сокрытия данных - все что есть основано лишь на соглашениях. (С другой стороны, реализация Python, написанная на C, может полностью скрыть детали реализации и контроль доступа к объекту при необходимости; это может быть использовано расширениями Python, написанными на C.) </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Клиенты должны использовать атрибуты данных с осторожностью - клиенты могут испортить постоянные, поддерживаемые методами, &quot;штампуя&quot; на их атрибуты данных. Обратите внимание, что клиенты могут добавить свои атрибуты данных экземплярному объекту без использования существующих методов до тех пор, пока не возникает конфликта имен; - опять же, соглашение об именах позволит избежать головной боли. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Не существует сокращений для того, чтобы сослаться на атрибуты данных (или другие методы!) изнутри методов. Я считаю, что это на самом деле повышает удобство чтения методов: нет шансов запутаться в локальных переменных и переменных экземпляра, когда просматриваешь методы. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Часто первый аргумент метода называется <span style=" font-family:'Courier New,courier';">self</span>. Это не более, чем соглашение: имя <span style=" font-family:'Courier New,courier';">self</span> не имеет абсолютно никакого особого значение для Python. Однако следует отметить, что если не следовать соглашению, то ваш код может быть менее читаемым для других программистов Python, и также возможно, что класс browser программы может быть написан, полагаясь на такое соглашение. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Любой объект-функция, которая является атрибутом класса, определяет метод для экземпляров этого класса. Не обязательно, чтобы определение функции текстуально заключалось в определении класса: присваивание объекта-функции локальной переменной в классе также возможно. Например: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"># Функция определяется вне класса</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">def f1(self, x, y):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    return min(x, x+y)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class C:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    f = f1</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def g(self):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        return 'hello world'</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    h = g</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Теперь и <span style=" font-family:'Courier New,courier';">f</span>, и <span style=" font-family:'Courier New,courier';">g</span>, и <span style=" font-family:'Courier New,courier';">h</span> являются атрибутами класса C, который ссылается на функции-объекты, и, следовательно, все они являются методами экземпляров класса C - <span style=" font-family:'Courier New,courier';">h</span> есть точный эквивалент <span style=" font-family:'Courier New,courier';">g</span>. Обратите внимание, что эта практика, как правило, способна лишь запутать читателя программы. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Методы могут вызывать другие методы путем использования аргумента <span style=" font-family:'Courier New,courier';">self</span>: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class Bag:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def __init__(self):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.data = []</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def add(self, x):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.data.append(x)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def addtwice(self, x):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.add(x)</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.add(x)</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Методы могут ссылаться на глобальные имена также, как и обычные функции. Глобальная область видимости, ассоциированная с методом, есть модуль, содержащий его определение. (Класс никогда не используется как глобальная область). Поскольку это редко встречается, то это хороший повод для использования глобальных данных в методе, есть много уместных использований глобальной области: с одной стороны, функции и модули, импортированные в глобальную область видимости, могут использоваться методами также как функциями и классами, определенными здесь. Как правило, класс, содержащий метод, сам по себе определяется в этой глобальной области видимости, и в следующем разделе мы найдем несколько хороших причин, почему метод хотел бы ссылаться на свой собственный класс. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Каждое значение является объектом, и поэтому имеет класс (также называемый его типом). Он хранится как <span style=" font-family:'Courier New,courier';">object.__class__</span>. </p>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="inheritance"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.5. Наследование</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Несомненно свойство языка не имела бы право называться &quot;классом&quot; без поддержки наследования. Синтаксис для определения производного класса выглядит следующим образом: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class DerivedClassName(BaseClassName):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    &lt;statement-1&gt;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    &lt;statement-N&gt;</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Имя <span style=" font-family:'Courier New,courier';">BaseClassName</span> должны быть определено в пределах области видимости производного класса. На месте имени базового класса также допускается иные произвольные выражения. Это может быть использовано, например, когда базовый класс определен в другом модуле: </p>
<pre style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class DerivedClassName(modname.BaseClassName):</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Выполнение определения производного класса протекает так же, как для базового класса. Когда объект класса создается, базовый класс запоминается. Это используется для выяснения ссылок на атрибуты: если запрошенный атрибут не найден в классе, поиск продолжается в базовом классе. Это правило применяется рекурсивно, если сам базовый класс является производным от другого класса. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Нет ничего особенного в экземплярах производных классов: <span style=" font-family:'Courier New,courier';">DerivedClassName</span><span style=" font-family:'Courier New,courier'; color:#000000;">()</span> создает новый экземпляр класса. Ссылки на методы разрешаются следующим образом: требуемый атрибут класса ищется по убыванию вниз по цепочке базовых классов, если это необходимо, и ссылка на метод работает, если она дает объект функции. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Производные классы могут переопределить методы их базовых классов. Потому как методы не имеют особых привилегий при вызове других методов того же объекта, так метод базового класса, что вызывает другой метод, определенный в том же базовом классе, может в конечном итоге вызвать метод производного класса, который переопределяет его. (Для программистов на C++: все методы в Python фактически являются <span style=" font-family:'Courier New,courier';">virtual</span>.) </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Переопределенный метод в производном классе на самом деле может потребоваться расширить, а не просто заменить метод базового класса с тем же именем. Существует простой способ вызвать метод базового класса напрямую: просто напишите <span style=" font-family:'Courier New,courier';">BaseClassName.methodname(self, arguments)</span>. Это также иногда полезно для клиентов. (Заметим, что это работает только если базовый класс доступен как <span style=" font-family:'Courier New,courier';">BaseClassName</span> в глобальной области видимости.) </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">У Python есть две встроенные функции, которые работают с наследованием: </p>
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Используйте isinstance(), чтобы проверить тип экземпляра: <span style=" font-family:'Courier New,courier';">isinstance(obj, int)</span> вернет <span style=" font-family:'Courier New,courier';">True</span>, если только <span style=" font-family:'Courier New,courier';">obj.__class__</span> является int или некоторый класс, производный от int. </li>
<li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Используйте issubclass() для проверки наследования классов: <span style=" font-family:'Courier New,courier';">issubclass(bool, int)</span> есть <span style=" font-family:'Courier New,courier';">True</span>, поскольку bool - это подкласс int. Однако, <span style=" font-family:'Courier New,courier';">issubclass(float, int)</span> ложно, так как float не является подклассом int.</li></ul>
<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="multiple-inheritance"></a><span style=" font-size:large; font-weight:600;">9</span><span style=" font-size:large; font-weight:600;">.5.1. Множественное наследование</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Python также поддерживает форму множественного наследования. Определение класса с несколькими базовыми классами выглядит следующим образом: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class DerivedClassName(Base1, Base2, Base3):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    &lt;statement-1&gt;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    .</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    &lt;statement-N&gt;</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Для большинства целей, в простейших случаях, вы можете думать о поиске атрибутов, унаследованных от родительского класса, как сначала в глубину, затем слева-направо, не ищет дважды в том же классе, где есть совпадение в иерархии. Таким образом, если атрибут не найден в <span style=" font-family:'Courier New,courier';">DerivedClassName</span>, он ищется в <span style=" font-family:'Courier New,courier';">Base1</span>, затем (рекурсивно) в базовых классах <span style=" font-family:'Courier New,courier';">Base1</span>, и если не был найден там, поиск будет продолжен в <span style=" font-family:'Courier New,courier';">Base2</span> и так далее. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">На самом деле все немного сложнее; порядок выбора метода динамически изменяется для поддержки совместных вызовов к <a href="http://pythoner.name/documentation/library/functions#super"><span style=" font-family:'Courier New,courier'; text-decoration: underline; color:#0000ff;">super()</span></a>. Такой подход известен в некоторых других языках с множественным наследованием как &quot;вызов следующего метода&quot; и является более мощным, чем вызов super, присутствующего в языках с одиночным наследованием. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Динамическое следование необходимо потому, что все случаи множественного наследования обладают одним или несколькими взаимосвязанными отношениями (где по крайней мере один из родительских классов может быть доступен через множество путей от самого нижнего класса). Например, все классы унаследованы от <a href="http://pythoner.name/documentation/library/functions#object"><span style=" font-family:'Courier New,courier'; text-decoration: underline; color:#0000ff;">object</span></a>, так что любой случай множественного наследования обеспечивает более одного пути, чтобы добраться до <span style=" font-family:'Courier New,courier';">object</span>. Чтобы сохранить базовые классы от доступа более одного раза, динамический алгоритм делает линейным порядок поиска таким образом, чтобы сохранить порядок слева-направо, указанный в каждом классе, который вызывает каждого родителя только один раз (это означает, что от класса можно создать подкласс не затрагивая порядок приоритетов его родителей). Взятые вместе эти свойства делают возможным создание надежных и расширяемых классов с множественным наследованием. Более подробно см. python.org/download/releases/2.3/mro/. </p>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="private-variables"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.6. Приватные переменные</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">В Python не существует &quot;частных&quot; (приватных) переменных экземпляра, т.е. тех, которые не могут быть доступны, кроме как изнутри объекта. Тем не менее есть соглашение, которое поддерживается большей частью кода Python: идентификатор с префиксом нижней черты (например <span style=" font-family:'Courier New,courier';">_spam</span>) должны рассматриваться как непубличная часть API (будь то функция, метод или элемент данных). Следует учитывать, детали реализации и предмет могут быть изменены без предварительного уведомления. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Поскольку есть действительные прецеденты для приватных членов класса (а именно, чтобы избежать конфликтов имен с именами, определенными подклассами), есть ограниченная поддержка такого механизма, называемого корректировкой имен (<span style=" font-style:italic;">name mangling</span>). Любой идентификатор вида <span style=" font-family:'Courier New,courier';">__spam</span> (по крайней мере с двумя первыми подчеркиваниями и не более чем одним завершающим) текстуально заменяются на <span style=" font-family:'Courier New,courier';">_classname__spam</span>, где <span style=" font-family:'Courier New,courier';">classname</span> - это текущее имя класса с начальным символом(ами) подчеркивания. Эта корректировка делается безотносительно к синтаксической позиции идентификатора до тех пор, пока это происходит в определении класса. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Корректировка имен полезна для того, чтобы позволить подклассам переопределять методы, не нарушая внутриклассовых вызовов методов. Например: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class Mapping:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def __init__(self, iterable):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.items_list = []</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.__update(iterable)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def update(self, iterable):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        for item in iterable:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">            self.items_list.append(item)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    __update = update   # приватная копия оригинального метода update()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class MappingSubclass(Mapping):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def update(self, keys, values):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        # предоставляет новую подпись для update()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        # но не ломает __init__()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        for item in zip(keys, values):</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">            self.items_list.append(item)</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Хотя в основном правила корректировки предназначены для избежания несчастных случаев, но все равно можно получить доступ или изменить переменную, которая считается приватной. Это даже может быть полезно при особых обстоятельствах, например, в отладчике. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Обратите внимание, что код, передающийся <span style=" font-family:'Courier New,courier';">exec()</span> или <span style=" font-family:'Courier New,courier';">eval()</span>, не учитывает имя класса вызывающего класса к текущему классу; это похоже на эффект оператора <span style=" font-family:'Courier New,courier';">global</span>, эффект, который также ограничивается кодом, который байт-скомпилированный вместе. То же ограничение применяется к <span style=" font-family:'Courier New,courier';">getattr()</span>, <span style=" font-family:'Courier New,courier';">setattr()</span> и <span style=" font-family:'Courier New,courier';">delattr()</span>, а также при обращении к <span style=" font-family:'Courier New,courier';">__dict__</span> напрямую. </p>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="odds-and-ends"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.7. Различные заметки</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Иногда бывает полезно иметь тип данных похожий на запись в Паскале или структуру в C, связав вместе несколько именованных элементов данных. Определение пустого класса превосходно представит такую возможность: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class Employee:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    pass</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">john = Employee() # Создает пустую запись employee</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"># Заполняются поля записи</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">john.name = 'John Doe'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">john.dept = 'computer lab'</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">john.salary = 1000</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Часть кода Python, который ожидает определенного абстрактного типа данных, часто может быть передан классу, который эмулирует методы вместо этого типа данных. Например, если у вас есть функция, которая форматирует некоторые данные из файлового объекта, вы можете определить класс с методами <span style=" font-family:'Courier New,courier';">read()</span> и <span style=" font-family:'Courier New,courier';">readline()</span>, которые вместо этого получают данные из буфера строки, и передают их в качестве аргумента. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Объекты методов экземпляра имеют атрибуты также: <span style=" font-family:'Courier New,courier';">m.__self__</span> является объектом экземпляра с методом <span style=" font-family:'Courier New,courier';">m()</span>, и <span style=" font-family:'Courier New,courier';">m.__func__</span> является объектом функцией, соответствующей этому методу. </p>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="iterators"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.8. Итераторы</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">К этому моменту вы возможно заметили, что большинство контейнерных объектов позволяют совершить по ним циклический проход с помощью оператора for (docs.python.org/3/reference/compound_stmts.html#for): </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">for element in [1, 2, 3]:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(element)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">for element in (1, 2, 3):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(element)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">for key in {'one':1, 'two':2}:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(key)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">for char in &quot;123&quot;:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(char)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">for line in open(&quot;myfile.txt&quot;):</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    print(line, end='')</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Этот стиль доступа является ясным, кратким, и удобным. Использование итераторов пронизывает и объединяет Python. За сценой оператор for вызывает <a href="http://pythoner.name/documentation/library/functions#iter"><span style=" text-decoration: underline; color:#0000ff;">iter()</span></a> на объект-контейнер. Эта функция возвращает объект-итератор, который определяет метод <a href="http://pythoner.name/documentation/library/stdtypes#iterator.__next__"><span style=" text-decoration: underline; color:#0000ff;">__next__()</span></a>, который выбирает элементы контейнера по одному за раз. Когда больше элементов нет, __next__() вызывает исключение StopIteration (docs.python.org/3/library/exceptions.html#StopIteration), которое заставляет цикл for завершиться. Вы можете вызвать метод __next__() с помощью встроенной функции next(); этот пример показывает, как все это работает: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; s = 'abc'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; it = iter(s)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; it</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&lt;iterator object at 0x00A1DB50&gt;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; next(it)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">'a'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; next(it)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">'b'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; next(it)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">'c'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; next(it)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">Traceback (most recent call last):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">  File &quot;&lt;stdin&gt;&quot;, line 1, in ?</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    next(it)</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">StopIteration</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Увидев как работает механизм протокола итератора, легко добавить поведение итератора в классы. Определите метод __iter__(), который возвращает объект с методом __next__(). Если класс определяет __next__(), затем __iter__(), то можно просто вернуть <span style=" font-family:'Courier New,courier';">self</span>: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">class Reverse:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    &quot;&quot;&quot;Итератор для обхода последовательности наоборот.&quot;&quot;&quot;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def __init__(self, data):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.data = data</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.index = len(data)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def __iter__(self):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        return self</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    def __next__(self):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        if self.index == 0:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">            raise StopIteration</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        self.index = self.index - 1</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        return self.data[self.index]</span> </pre>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; rev = Reverse('spam')</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; iter(rev)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&lt;__main__.Reverse object at 0x00A1DB50&gt;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; for char in rev:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">...     print(char)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">...</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">m</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">a</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">p</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">s</span> </pre>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="generators"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.9. Генераторы</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Генераторы</span> (docs.python.org/3/glossary.html#term-generator) представляют собой простой и мощный инструмент для создания итераторов. Они написаны как обычные функции, но используют оператор <span style=" font-family:'Courier New,courier';">yield</span> (docs.python.org/3/reference/simple_stmts.html#yield), всякий раз когда требуется вернуть данные. Каждый раз <a href="http://pythoner.name/documentation/library/functions#next"><span style=" font-family:'Courier New,courier'; text-decoration: underline; color:#0000ff;">next()</span></a> вызывается на это, генератор возвращается туда, где был до этого (он запоминает все значения и какой оператор был выполнен последним). Пример показывает, как можно легко создать генератор: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">def reverse(data):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">    for index in range(len(data)-1, -1, -1):</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">        yield data[index]</span> </pre>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; for char in reverse('golf'):</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">...     print(char)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">...</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">f</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">l</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">o</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">g</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Все, что может быть сделано с помощью генераторов, также может быть сделано с итераторами на основе классов, как описано в предыдущем разделе. То, что делает генераторы настолько компактными, это методы <span style=" font-family:'Courier New,courier';">__iter__()</span> и <span style=" font-family:'Courier New,courier';">__next__()</span>, которые создаются автоматически. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Еще одной ключевой особенностью является то, что локальные переменные и состояние выполнения автоматически сохраняются между вызовами. Это сделало функцию легче для написания и гораздо яснее, чем подход с использованием переменных экземпляра, как <span style=" font-family:'Courier New,courier';">self.index</span> и <span style=" font-family:'Courier New,courier';">self.data</span>. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">В дополнение к автоматическому созданию метода и сохранению состояния программы, когда генераторы прекращают работу, они автоматически возбуждают StopIteration (docs.python.org/3/library/exceptions.html#StopIteration). В сочетании эти особенности позволяют легко создавать итераторы с не большими усилиями, чем писать обычные функции. </p>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="generator-expressions"></a><span style=" font-size:x-large; font-weight:600;">9</span><span style=" font-size:x-large; font-weight:600;">.10. Выражения с использованием генераторов</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Некоторые простые генераторы могут быть закодированы лаконично как выражения, используя синтаксис, аналогичный списку, но с круглыми скобками вместо квадратных. Эти выражения предназначены для ситуаций, когда генератор используется сразу же включающей функцией. Выражения с генератором более компактные, но менее универсальные, чем полные определения генераторов и, как правило, быть более дружелюбны, чем эквивалентное использование списков. </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Примеры: </p>
<pre style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; sum(i*i for i in range(10))                 # сумма квадратов</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">285</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; xvec = [10, 20, 30]</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; yvec = [7, 5, 3]</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; sum(x*y for x,y in zip(xvec, yvec))         # dot product</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">260</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; from math import pi, sin</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; sine_table = {x: sin(x*pi/180) for x in range(0, 91)}</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; unique_words = set(word  for line in page  for word in line.split())</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; valedictorian = max((student.gpa, student.name) for student in graduates)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> </span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; data = 'golf'</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">&gt;&gt;&gt; list(data[i] for i in range(len(data)-1, -1, -1))</span></pre>
<pre style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">['f', 'l', 'o', 'g']</span> </pre>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Примечания</span> </p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="id11"></a><a href="http://pythoner.name/documentation/tutorial/classes#id1"><span style=" text-decoration: underline; color:#0000ff;">[</span></a><span style=" text-decoration: underline; color:#0000ff;">1]</span> За исключением одной вещи. У объектов модуля есть секретный атрибут только для чтения атрибут <a href="http://pythoner.name/documentation/library/stdtypes#object.__dict__"><span style=" text-decoration: underline; color:#0000ff;">__dict__</span></a>, который возвращает словарь, используемый для реализации пространства имен модуля; имя __dict__ является атрибутом, но не глобальным именем. Очевидно, что его использование нарушает абстракцию реализации пространства имен, и должно быть ограничена к вещам, как завершающие действия отладчиков.</p>
<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large; font-weight:600;">Создано</span></p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2013-05-05 </p>
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/comment/reply/node/35/comment#comment-form"><span style=" text-decoration: underline; color:#0000ff;">Добавить комментарий</span></a> </li></ul>
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a name="book-label-26"></a><span style=" font-size:x-large; font-weight:600;">П</span><span style=" font-size:x-large; font-weight:600;">ерекрёстные ссылки книги для 9. Классы</span> </p>
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/exceptions"><span style=" text-decoration: underline; color:#0000ff;">8. Ошибки и исключения</span></a> </li>
<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial"><span style=" text-decoration: underline; color:#0000ff;">Вверх</span></a> </li>
<li style="" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://pythoner.name/documentation/tutorial/library"><span style=" text-decoration: underline; color:#0000ff;">10. Краткий обзор стандартной библиотеки</span></a> </li></ul></body></html>